package cn.ibizlab.odoo.core.util.aspect;

import cn.ibizlab.odoo.core.util.annotation.DEField;
import cn.ibizlab.odoo.core.util.enums.DEFieldDefaultValueType;
import cn.ibizlab.odoo.core.util.helper.DEFieldCacheMap;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 实体属性默认值切面，只有新建（Create）时才会填充默认值
 */
@Aspect
@Order(0)
@Component
public class DEFieldDefaultValueAspect
{
    /**
     * 新建数据切入点
     * @param point
     * @throws Exception
     */
    @Before(value = "execution(* cn.ibizlab.odoo.core.*.service.*.create(..))")
    public void BeforeCreate(JoinPoint point) throws Exception {
        fillDEFieldDefaultValue(point);
    }

    /**
     * 保存数据切入点
     * @param point
     * @throws Exception
     */
    @Before(value = "execution(* cn.ibizlab.odoo.core.*.service.*.save(..))")
    public void BeforeSave(JoinPoint point) throws Exception {
        checkAction(point);
    }

    /**
     * 判断当前是否为新建操作，若为新建，则填充属性默认值
     * @param joinPoint
     * @throws Exception
     */
    private void checkAction(JoinPoint joinPoint) throws Exception {

        Object[] args = joinPoint.getArgs();
        if (args.length > 0) {
            Object obj = args[0];
            String className=obj.getClass().getName();
            //获取当前do对象中的属性
            DEFieldCacheMap.getFieldMap(className);
            //从属性列表中过滤出主键属性
            Field keyPSDEField = this.getKeyPSDEField(className);

            if(ObjectUtils.isEmpty(keyPSDEField))
                return ;

            String filename = keyPSDEField.getName();
            PropertyDescriptor field = new PropertyDescriptor(filename, obj.getClass());
            Method fieldGetMethod = field.getReadMethod();
            //获取主键值
            Object fieldValue = fieldGetMethod.invoke(obj);
            //实体数据主键为空，则为新建操作，填充属性默认值
            if(ObjectUtils.isEmpty(fieldValue)){
                fillDEFieldDefaultValue(joinPoint);
            }
        }
    }

    /**
     * 获取主键属性
     * @param className 实体类名
     * @return 主键属性
     */
    private Field getKeyPSDEField(String className){

        Field keyField =null;
        List<Field> fields =  DEFieldCacheMap.getFields(className);

        for(Field field:fields){
            DEField deField=field.getAnnotation(DEField.class);
            if(!ObjectUtils.isEmpty(deField) && deField.isKeyField()) {
                return field;
            }
        }

        return keyField;
    }

    /**
     * 填充属性默认值
     * @param joinPoint
     * @return
     * @throws Exception
     */
    public Object fillDEFieldDefaultValue(JoinPoint joinPoint) throws Exception {

        Object[] args = joinPoint.getArgs();
        if (args.length > 0) {
            Object obj = args[0];
            String className=obj.getClass().getName();
            //获取当前po对象中的属性
            DEFieldCacheMap.getFieldMap(className);
            //从属性列表中过滤出预置属性
            Map<Field, DEField> deFields = this.SearchDEField(className);
            //填充预置属性
            fillDEField(obj, deFields);
            return true;
        }
        return true;
    }

    /**
     *获取含有@DEField注解的实体属性
     * @param className do对象类名
     * @return
     */
    private Map <Field, DEField> SearchDEField(String className){

        List<Field> fields =  DEFieldCacheMap.getFields(className);
        Map <Field, DEField> deFieldMap =new HashMap<>();
        for(Field field:fields){
            DEField deField=field.getAnnotation(DEField.class);
            if(!ObjectUtils.isEmpty(deField)) {
                deFieldMap.put(field,deField);
            }
        }
        return deFieldMap;
    }

    /**
     * 填充系统预置属性
     * @param et   当前实体对象
     */
    private void fillDEField(Object et, Map<Field, DEField> deFields) throws Exception {

        if(deFields.size()==0)
            return ;

        for (Map.Entry<Field, DEField> entry : deFields.entrySet()) {

            //获取预置属性
            Field deField=entry.getKey();
            String filename=deField.getName();
            //获取预置属性注解
            DEField fieldAnnotation=entry.getValue();
            //获取预置属性类型
            DEFieldDefaultValueType deFieldType=fieldAnnotation.defaultValueType();
            String deFieldDefaultValue = fieldAnnotation.defaultValue();

            //获取预置属性的get、set方法及字段值
            PropertyDescriptor field = new PropertyDescriptor(filename, et.getClass());
            Method fieldSetMethod = field.getWriteMethod();
            Method fieldGetMethod = field.getReadMethod();
            Object fieldValue = fieldGetMethod.invoke(et);

            //为默认值属性进行赋值
            if(org.springframework.util.StringUtils.isEmpty(fieldValue)){
                //填充直接值及其余默认值类型
                if( (deFieldType== DEFieldDefaultValueType.NONE && !StringUtils.isEmpty(deFieldDefaultValue))   || (deFieldType != DEFieldDefaultValueType.NONE) ){
                    switch(deFieldType){//根据注解给预置属性填充值
                        case SESSION:
                            break;
                        case SYSTEM:
                            break;
                        case UUID:
                            break;
                        case REQUEST:
                            break;
                        case DEFIELD:
                            break;
                        case OPPERSONID:
                            break;
                        case OPPERSONNAME:
                            break;
                        case NONE:
                            //对字段值进行类型转换
                            Object deFieldDefaultValueObj=fieldValueConvert(deFieldDefaultValue,field);
                            fieldSetMethod.invoke(et,deFieldDefaultValueObj);
                            break;
                    }
                }
            }
        }
    }
    /**
    * 值类型转换
    * @param fieldValue
    * @param field
    */
    private Object fieldValueConvert(String fieldValue,PropertyDescriptor field){

        Object resultValue=fieldValue;

        String targetType=field.getPropertyType().getSimpleName();

        if(targetType.equals("Boolean")){
            resultValue=Boolean.valueOf(fieldValue);
        }
        else if(targetType.equals("Character")){
            resultValue=fieldValue.toCharArray();
        }
        else if(targetType.equals("Byte")){
            resultValue=Byte.valueOf(fieldValue);
        }
        else if(targetType.equals("Short")){
            resultValue=Short.valueOf(fieldValue);
        }
        else if(targetType.equals("Integer")){
            resultValue= Integer.valueOf(fieldValue);
        }
        else if(targetType.equals("Long")){
            resultValue=Long.valueOf(fieldValue);
        }
        else if(targetType.equals("Float")){
            resultValue= Float.valueOf(fieldValue);
        }
        else if(targetType.equals("Double")){
            resultValue= Double.valueOf(fieldValue);
        }
        return resultValue;
    }
}
